package com.xms.schema.service.entity;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xms.core.config.FinalValueDefaults;
import com.xms.core.exception.XmsException;
import com.xms.datacore.IMetadataProvider;
import com.xms.datacore.service.CreaterService;
import com.xms.event.core.IEventPublisher;
import com.xms.schema.core.AttributeDescriptor;
import com.xms.schema.core.AttributeTypeIds;
import com.xms.schema.entity.Attribute;
import com.xms.schema.entity.Entity;
import com.xms.schema.entity.RelationShip;
import com.xms.schema.event.EntityMetaCreatedEvent;
import com.xms.schema.extension.AttributeExt;
import com.xms.schema.service.attribute.DefaultAttributeDatas;
import com.xms.schema.service.attribute.IAttributeCreaterService;
import com.xms.schema.service.attribute.IDefaultAttributeProvider;
import com.xms.utils.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * EntityCreater
 * </p>
 *
 * @author migo
 * @since 2021/9/2
 */
@CacheConfig(cacheNames = "schema.entity", keyGenerator = "CacheKeyGenerator")
@Service
public class EntityCreaterService extends CreaterService<Entity> implements IEntityCreaterService {
    private IMetadataProvider _metadataProvider;
    private IDefaultAttributeProvider _defaultAttributeProvider;
    private IAttributeCreaterService _attributeCreaterService;
    private IEventPublisher _eventPublisher;

    @Autowired
    public EntityCreaterService(IMetadataProvider metadataProvider
            , IDefaultAttributeProvider defaultAttributeProvider
            , IAttributeCreaterService attributeCreaterService
            , IEventPublisher eventPublisher) {
        _metadataProvider = metadataProvider;
        _defaultAttributeProvider = defaultAttributeProvider;
        _attributeCreaterService = attributeCreaterService;
        _eventPublisher = eventPublisher;
    }

    private boolean createCore(Entity entity, DefaultAttributeDatas defaultAttributeDatas) throws SQLException, XmsException {
        LambdaQueryWrapper<Entity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Entity::getName, entity.getName());
        if (super.count(queryWrapper) > 0) {
            throw new XmsException("名称已存在");
        }
        boolean success = super.create(entity);
        if(success) {
            List<Attribute> defaultAttributes = defaultAttributeDatas.attributes;
            List<RelationShip> defaultRelationShips = defaultAttributeDatas.relationships;
            //创建数据库表
            _metadataProvider.createTable(entity, defaultAttributes);
            //创建视图
            _metadataProvider.alterView(entity, defaultAttributes, defaultRelationShips);
            //插入默认字段
            _attributeCreaterService.createDefaultAttributes(entity, defaultAttributeDatas);
            //如果是子实体，则创建引用字段
            if (entity.getParententityid() != null) {
                Entity parentEntity = super.getService().getById(entity.getParententityid());
                if (parentEntity != null) {
                    Attribute refAttr = new Attribute();
                    refAttr.setAttributeid(UUID.randomUUID());
                    refAttr.setName(parentEntity.getName() + "id");
                    refAttr.setAttributetypename(AttributeTypeIds.LOOKUP);
                    refAttr.setEntityid(entity.getEntityid());
                    refAttr.setEntityname(entity.getName());
                    refAttr.setLocalizedname(parentEntity.getLocalizedname());
                    refAttr.setReferencedentityid(parentEntity.getEntityid());
                    refAttr.setIsnullable(true);
                    refAttr.setIsrequired(true);
                    refAttr.setLogenabled(false);
                    refAttr.setIscustomizable(false);
                    refAttr.setIscustomfield(false);
                    refAttr.setAuthorizationenabled(false);
                    refAttr.setIsprimaryfield(false);
                    refAttr.setCreatedon(LocalDateTime.now());
                    refAttr.setCreatedby(FinalValueDefaults.ADMIN_USERID);
                    _attributeCreaterService.create(new AttributeDescriptor(refAttr));
                }
            }
            //发布实体创建事件
            _eventPublisher.publish(new EntityMetaCreatedEvent(entity));
        }
        return success;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean create(Entity entity, List<String> defaultAttributes) throws SQLException, XmsException {
        DefaultAttributeDatas defaultAttributeDatas = _defaultAttributeProvider.getSysAttributes(entity);
        if (CollectionUtil.notEmpty(defaultAttributes)) {
            defaultAttributeDatas.attributes.removeIf(x -> !AttributeExt.typeIsPrimaryKey(x) && !defaultAttributes.contains(x.getName()));
            defaultAttributeDatas.relationships.removeIf(x -> !defaultAttributes.contains(x.getReferencingattributename()));
        } else {
            defaultAttributeDatas.attributes.removeIf(x -> !AttributeExt.typeIsPrimaryKey(x));
            defaultAttributeDatas.relationships.clear();
        }
        return this.createCore(entity, defaultAttributeDatas);
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean create(Entity entity) throws SQLException, XmsException {
        DefaultAttributeDatas defaultAttributeDatas = _defaultAttributeProvider.getSysAttributes(entity);
        return this.createCore(entity, defaultAttributeDatas);

    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean createMany(Collection<Entity> entityList) throws SQLException, XmsException {
        if (CollectionUtil.notEmpty(entityList)) {
            for (Entity entity : entityList) {
                this.create(entity);
            }
        }
        return true;
    }
}
